package com.jiangyao.service.impl;

import com.alibaba.excel.EasyExcel;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.jiangyao.common.constants.AdminUserConstants;
import com.jiangyao.common.exception.ServerException;
import com.jiangyao.common.utils.MD5util;
import com.jiangyao.common.utils.StringUtils;
import com.jiangyao.common.utils.ValidateUtil;
import com.jiangyao.component.SMSComponent;
import com.jiangyao.dao.*;
import com.jiangyao.model.dto.ClassInfoDto;
import com.jiangyao.model.dto.ClassUserDto;
import com.jiangyao.model.dto.backend.ClassUserAddDTO;
import com.jiangyao.model.dto.backend.ClassUserDTO;
import com.jiangyao.model.dto.backend.ClassUserListPageDTO;
import com.jiangyao.model.entity.*;
import com.jiangyao.model.vo.AdminUserSessionVO;
import com.jiangyao.model.vo.ClassmateVo;
import com.jiangyao.model.vo.UserClassVo;
import com.jiangyao.model.vo.backend.ClassUserDetailVO;
import com.jiangyao.model.vo.backend.OrgInfoClassUserExcelVO;
import com.jiangyao.service.ClassInfoService;
import com.jiangyao.service.ClassUserService;
import com.jiangyao.service.UserService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FilenameUtils;
import org.dozer.DozerBeanMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;

/**
 * <p>
 * 班级成员信息 服务实现类
 * </p>
 *
 * @author xiangyan
 * @since 2020-08-13
 */
@Service
@Slf4j
public class ClassUserServiceImpl extends BaseServiceImpl<IClassUserDao, ClassUser> implements ClassUserService {

	@Autowired
	private DozerBeanMapper dozerBeanMapper;

	@Autowired
	private IClassUserDao classUserDao;

	@Autowired
	private IOrgInfoDao orgInfoDao;

	@Autowired
	private ClassInfoService classInfoService;

	@Autowired
	private IClassUserScoreDao iClassUserScoreDao;

	@Autowired
	private UserService userService;

	@Autowired
	private IUserDao iUserDao;

	@Autowired
	private IProgressDao iProgressDao;

	@Override
	public List<UserClassVo> getWebUserClass() {
		ClassUserDto dto = new ClassUserDto();
		dto.setUserId(getLoginApiUserId());
		List<UserClassVo> list = classUserDao.getWebUserClass(dto);
		setClassMate(list);
		return list;
	}

	private void setClassMate(List<UserClassVo> list) {
		for (UserClassVo vo : list) {
			QueryWrapper<ClassUser> query = new QueryWrapper();
			query.eq("class_id", 1).eq("status", 1);
			vo.setClassMate(this.count(query));
		}

	}

	@Override
	public Boolean applyForOrg(ClassUserDto classUserDto) {
		QueryWrapper<ClassUser> queryWrapper = new QueryWrapper<>();
		queryWrapper.eq("org_id", classUserDto.getOrgId()).eq("user_id", classUserDto.getUserId())
				.eq("class_id", classUserDto.getClassId()).eq("status", 1);
		queryWrapper.last(" LIMIT 1");
		ClassUser exist = this.getOne(queryWrapper);
		if (exist != null) {
			throw new ServerException(303, "已是该组织的成员");
		}
		ClassUser classUser = dozerBeanMapper.map(classUserDto, ClassUser.class);
		classUser.setCreateTime(new Date());
		classUser.setApplyType(2);
		classUser.setStatus(1);
		this.save(classUser);
		return true;
	}

	@Override
	public void downloadImportTemplate(HttpServletResponse response) {
		try {
			AdminUserSessionVO adminUserSessionVO = getAdminLoginSession();
			List<OrgInfoClassUserExcelVO> list = new ArrayList<>(1);
			if (!CollectionUtils.isEmpty(adminUserSessionVO.getClassIdList())) {
				Integer classId = adminUserSessionVO.getClassIdList().get(0);
				ClassInfo classInfo = classInfoService.getById(classId);
				if (classInfo != null) {
					list.add(OrgInfoClassUserExcelVO.builder().orgId(classInfo.getOrgId()).classId(classId).build());
				}
			} else if (!CollectionUtils.isEmpty(adminUserSessionVO.getOrgIdList())) {
				list.add(OrgInfoClassUserExcelVO.builder().orgId(adminUserSessionVO.getOrgIdList().get(0)).build());
			}
			String fileName = URLEncoder.encode("成员导入", "UTF-8");
			response.setHeader("Content-disposition", "attachment;filename=" + fileName + ".xlsx");
			EasyExcel.write(response.getOutputStream(), OrgInfoClassUserExcelVO.class).sheet("成员导入").doWrite(list);
		} catch (Exception e) {
			log.error("下载组织班级成员导入模板失败，error:{}", e.getMessage(), e);
		}
	}

	@Override
	public void importUser(MultipartFile file) {
		String fileName = file.getOriginalFilename();
		String suffix = FilenameUtils.getExtension(fileName);
		if (StringUtils.isBlank(suffix) || !suffix.toLowerCase().contains("xls")) {
			throw new ServerException(100, "文件格式不正确");
		}
		try {
			List<OrgInfoClassUserExcelVO> userExcelVOList = EasyExcel.read(file.getInputStream(), OrgInfoClassUserExcelVO.class,
					null).doReadAllSync();
			// 检查导入成员信息
			checkImportFileData(userExcelVOList);
			// 处理用户
			userExcelVOList = handleUserForImport(userExcelVOList);
			// 保存班级成员
			saveUserClass(userExcelVOList);
		} catch (ServerException e) {
			throw e;
		} catch (Exception e) {
			log.error("导入组织班级成员失败，error:{}", e.getMessage(), e);
		}
	}


	/**
	 * 检查导入成员信息
	 *
	 * @param userExcelVOList 成员信息列表
	 */
	private void checkImportFileData(List<OrgInfoClassUserExcelVO> userExcelVOList) {
		if (CollectionUtils.isEmpty(userExcelVOList)) {
			throw new ServerException(100, "文件为空");
		}
		Integer orgId = null;
		Integer classId = null;
		int line = 2;
		for (OrgInfoClassUserExcelVO excelVO : userExcelVOList) {
			if (excelVO.getOrgId() == null || excelVO.getOrgId() < 1) {
				throw new ServerException(100, "第" + line + "行：组织ID不能为空");
			}
			if (orgId != null && !orgId.equals(excelVO.getOrgId())) {
				throw new ServerException(100, "一次只能导入一个组织");
			}
			orgId = excelVO.getOrgId();
			if (classId != null && !classId.equals(excelVO.getClassId())) {
				throw new ServerException(100, "一次只能导入一个班级");
			}
			classId = excelVO.getClassId();
			if (StringUtils.isBlank(excelVO.getUserName()) || excelVO.getUserName().length() < 2 || excelVO.getUserName().length() > 10) {
				throw new ServerException(100, "第" + line + "行：姓名不正确");
			}
			if (StringUtils.isBlank(excelVO.getUserPhone()) || excelVO.getUserPhone().length() != 11) {
				throw new ServerException(100, "第" + line + "行：手机号不正确");
			}

			if (StringUtils.isNotBlank(excelVO.getIdCard()) && !ValidateUtil.checkIdCardNo(excelVO.getIdCard())) {
				throw new ServerException(100, "第" + line + "行：身份证不正确");
			}
			if (StringUtils.isNotBlank(excelVO.getPosition()) && excelVO.getPosition().length() > 50) {
				throw new ServerException(100, "第" + line + "行：职位不正确");
			}
			line++;
		}
		OrgInfo orgInfo = orgInfoDao.selectById(orgId);
		if (orgInfo == null) {
			throw new ServerException(100, "导入组织ID有误或组织不存在");
		}
		if (classId != null && classId > 0) {
			ClassInfo classInfo = classInfoService.getById(classId);
			if (classInfo == null || !classInfo.getOrgId().equals(orgId)) {
				throw new ServerException(100, "导入班级ID有误或班级不存在");
			}
		}
	}

	/**
	 * 处理用户
	 * 1.根据手机号查询不存在用户，新增；
	 * 2.为本次导入所有用户设置用户ID
	 *
	 * @param userExcelVOList 导入成员信息
	 * @return 全新的导入成员信息
	 */
	private List<OrgInfoClassUserExcelVO> handleUserForImport(List<OrgInfoClassUserExcelVO> userExcelVOList) {
		List<String> userPhoneList = new ArrayList<>(userExcelVOList.size());
		Map<String, OrgInfoClassUserExcelVO> userExcelVOMap = Maps.newHashMapWithExpectedSize(userExcelVOList.size());
		userExcelVOList.forEach(excelVo -> {
			userPhoneList.add(excelVo.getUserPhone());
			userExcelVOMap.put(excelVo.getUserPhone(), excelVo);
		});
		QueryWrapper<User> queryWrapper = new QueryWrapper<>();
		queryWrapper.in("user_phone", userPhoneList);
		queryWrapper.select("user_id", "user_phone");
		List<User> userList = userService.list(queryWrapper);
		// 已存在用户手机号
		List<String> existUserPhoneList = new ArrayList<>(userExcelVOList.size());
		if (!CollectionUtils.isEmpty(userList)) {
			userList.forEach(user -> existUserPhoneList.add(user.getUserPhone()));
		}
		// 删除已存在的手机号（剩下的手机号没有用户对应）
		userPhoneList.removeAll(existUserPhoneList);

		if (userPhoneList.size() > 0) {
			// 新增用户列表
			List<User> newUserList = new ArrayList<>();
			Integer adminUserId = getLoginAdminUserId();
			Date now = new Date();
			String password = MD5util.generateSymbol(AdminUserConstants.DEFAULT_PASSWORD);
			userPhoneList.forEach(userPhone -> {
				OrgInfoClassUserExcelVO excelVO = userExcelVOMap.get(userPhone);
				if (excelVO != null) {
					User user = new User();
					user.setUserPhone(userPhone);
					user.setIdCard(excelVO.getIdCard());
					user.setPosition(excelVO.getPosition());
					user.setUserName(excelVO.getUserName());
					user.setPassword(password);
					user.setCreateTime(now);
					user.setCreateAdminId(adminUserId);
					user.setRegFrom(1);
					newUserList.add(user);
				}
			});
			userService.saveBatch(newUserList);
		}
		userPhoneList.addAll(existUserPhoneList);
		queryWrapper = new QueryWrapper<>();
		queryWrapper.in("user_phone", userPhoneList);
		queryWrapper.select("user_id", "user_phone");
		userList = userService.list(queryWrapper);

		List<OrgInfoClassUserExcelVO> newUserExcelVOList = new ArrayList<>(userList.size());
		userList.forEach(user -> {
			OrgInfoClassUserExcelVO excelVO = userExcelVOMap.get(user.getUserPhone());
			excelVO.setUserId(user.getUserId());
			newUserExcelVOList.add(excelVO);
		});

		return newUserExcelVOList;
	}


	/**
	 * 保存班级成员信息
	 * 1.将以前已经导入班级成员状态修改为正常
	 * 2.批量新增新的班级成员
	 *
	 * @param userExcelVOList 班级成员集合
	 */
	private void saveUserClass(List<OrgInfoClassUserExcelVO> userExcelVOList) {
		// 分批次处理
		List<List<OrgInfoClassUserExcelVO>> userExcelVOListList = Lists.partition(userExcelVOList, 200);
		Integer adminUserId = getLoginAdminUserId();
		for (List<OrgInfoClassUserExcelVO> subList : userExcelVOListList) {
			// 组织ID + "-" + 班级ID + "-" + 用户ID
			List<String> orgClassUserIdList = new ArrayList<>(subList.size());
			// 班级成员集合
			List<ClassUser> classUserList = new ArrayList<>(subList.size());
			for (OrgInfoClassUserExcelVO excelVO : subList) {
				ClassUser classUser = dozerBeanMapper.map(excelVO, ClassUser.class);
				if (classUser.getClassId() == null) {
					classUser.setClassId(0);
				}
				classUser.setCreateAdminId(adminUserId);
				classUserList.add(classUser);
				String orgClassUserId = classUser.getOrgId() + "_" + classUser.getClassId() + "_" + excelVO.getUserId();
				orgClassUserIdList.add(orgClassUserId);

			}
			// 将以前已经导入用户，状态修改为正常
			classUserDao.updateStatus(orgClassUserIdList, adminUserId, 1);
			// 批量新增班级成员
			classUserDao.insertBatch(classUserList);

		}
	}


	@Override
	public Page<ClassUserDetailVO> getListPage(ClassUserListPageDTO listPageDTO) {
		// 登录用户信息
		AdminUserSessionVO adminUserSessionVO = getAdminLoginSession();
		// 当前登录用户管理的组织ID集合(业务数据权限)
		listPageDTO.setOrgIdList(adminUserSessionVO.getOrgIdList());
		// 当前登录用户管理的班级ID集合(业务数据权限)
		listPageDTO.setClassIdList(adminUserSessionVO.getClassIdList());

		Page<ClassUserDetailVO> page = new Page<>(listPageDTO.getPageNo(), listPageDTO.getPageSize());
		classUserDao.getListPage(page, listPageDTO);
		return page;
	}

	@Override
	public void editStatus(ClassUserDTO classUserDTO) {
		UpdateWrapper<ClassUser> updateWrapper = new UpdateWrapper<>();
		updateWrapper.in("id", classUserDTO.getClassUserIdList());
		updateWrapper.set("status", classUserDTO.getStatus() != null ? classUserDTO.getStatus() : 1);
		updateWrapper.set("update_time", new Date());
		updateWrapper.set("update_admin_id", getLoginAdminUserId());
		this.update(updateWrapper);
	}

	@Override
	public void addUser(ClassUserAddDTO classUserAddDTO) {
		ClassInfo classInfo = classInfoService.getById(classUserAddDTO.getClassId());
		if (classInfo == null) {
			throw new ServerException(100, "班级不存在");
		}
		List<Integer> userIdList = classUserAddDTO.getUserIdList();
		if (CollectionUtils.isEmpty(userIdList)) {
			return;
		}
		// 查询已经在班级里面的成员列表
		QueryWrapper<ClassUser> queryWrapper = new QueryWrapper<>();
		queryWrapper.eq("org_id", classInfo.getOrgId()).eq("class_id", classInfo.getClassId())
				.in("user_id", userIdList).eq("status", 1);
		queryWrapper.select("id", "user_id");
		List<ClassUser> classUserList = this.list(queryWrapper);
		if (!CollectionUtils.isEmpty(classUserList)) {
			classUserList.forEach(classUser -> userIdList.remove(classUser.getUserId()));
		}
		if (CollectionUtils.isEmpty(userIdList)) {
			return;
		}
		Date now = new Date();
		Integer loginAdminUserId = getLoginAdminUserId();
		// 新班级成员集合
		List<ClassUser> addClassUserList = new ArrayList<>(userIdList.size());
		for (Integer userId : userIdList) {
			ClassUser classUser = new ClassUser();
			classUser.setOrgId(classInfo.getOrgId());
			classUser.setClassId(classInfo.getClassId());
			classUser.setUserId(userId);
			classUser.setCreateTime(now);
			classUser.setCreateAdminId(loginAdminUserId);
			classUser.setApplyType(1);
			classUser.setStatus(1);
			addClassUserList.add(classUser);
		}
		this.saveBatch(addClassUserList);
	}

	@Override
	public Integer getClassmateCount(ClassInfoDto classInfoDto) {
		QueryWrapper<ClassUser> classUserQueryWrapper = new QueryWrapper<>();
		classUserQueryWrapper.eq("org_id",classInfoDto.getOrgId())
				.eq("class_id",classInfoDto.getClassId());
		Integer count = baseMapper.selectCount(classUserQueryWrapper);
		return count;
	}

	@Override
	public List<ClassmateVo> getClassmate(ClassInfoDto classInfoDto) {
		List<ClassmateVo> classmate = classUserDao.getClassmate(classInfoDto);
		for (ClassmateVo classmateVo : classmate) {
			QueryWrapper<Progress> progressQueryWrapper = new QueryWrapper<>();
			progressQueryWrapper.eq("user_id",classmateVo.getUserId())
					.eq("class_id",classInfoDto.getClassId())
					.eq("status",2);
			Integer count = iProgressDao.selectCount(progressQueryWrapper);
			classmateVo.setStudyCount(count);
			QueryWrapper<User> userQueryWrapper = new QueryWrapper<>();
			userQueryWrapper.eq("user_id",classmateVo.getUserId());
			User user = iUserDao.selectOne(userQueryWrapper);
			if(null != user){
				classmateVo.setUserName(user.getUserName());
				classmateVo.setHeadImg("http://jy_test.nvnbd.com/ftp_jy/img/2020/20200917/head.png");
			}
		}
		return classmate;
	}
}
